#pragma once

#include <memory>
#include <string>

#include "abstract_rule.hpp"
#include "logical_query_plan/abstract_lqp_node.hpp"

namespace hyrise {

/**
 * A rule that brings join predicates of a multi-predicate join into an efficient order.
 *
 * Operators such as the hash join operate on the primary predicate, i.e., they hash the two columns that are compared
 * in the first predicate. Secondary predicates are evaluated using accessors, which is significantly more expensive.
 * Thus, a good predicate order is even more important than it is for regular (i.e., non-join) predicates.
 * Furthermore, the hash join only supports equals predicates, so the most selective equals predicate is moved to the
 * front.
 *
 * For inner joins, this is already done in AbstractJoinOrderingAlgorithm::_add_join_to_plan. However, we do it once
 * more here in this rule because the selectivities can be different after we transformed the plan, e.g., by a different
 * predicate placement or due to pruned chunks.
 */
class JoinPredicateOrderingRule : public AbstractRule {
 public:
  std::string name() const override;

 protected:
  void _apply_to_plan_without_subqueries(const std::shared_ptr<AbstractLQPNode>& lqp_root,
                                         OptimizationContext& optimization_context) const override;
};

}  // namespace hyrise
